package com.jl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jl.config.JLFeignConfig;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * feign拦截
 * get、put、delete
 * 1.属性入参，每个都需添加@RequestParam
 * 2.单实体入参，无需添加@RequestParam（经过二次封装）
 * post
 * 1.属性入参，每个都需添加@RequestParam
 * 2.单实体入参，需json方式，controller添加@RequestBody
 */
@Configuration
@AllArgsConstructor
public class JLFeignInterceptor implements RequestInterceptor {

    private ObjectMapper objectMapper;

    private JLFeignConfig feignParam;

    @Override
    public void apply(RequestTemplate template) {
        setHeader(template);
        sendPojo(template);
    }

    /**
     * 设置请求头
     *
     * @param template
     */
    public void setHeader(RequestTemplate template) {
        if (feignParam.getHead() != null) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                List<String> carrHeads = feignParam.getHead().getCarrHeads();
                Map<String, Object> setHeads = feignParam.getHead().getSetHeads();
                if (carrHeads != null) {
                    carrHeads.forEach(s -> template.header(s, request.getHeader(s)));
                }
                if (setHeads != null) {
                    Set<String> keys = setHeads.keySet();
                    Iterator<String> iterator = keys.iterator();
                    while (iterator.hasNext()) {
                        String key = iterator.next();
                        template.header(key, setHeads.get(key).toString());
                    }
                }
            }
        }
    }

    /**
     * feign不支持 GET，PUT，DELETE 方法传 POJO, 把json body转query
     *
     * @param template
     */
    @SneakyThrows
    public void sendPojo(RequestTemplate template) {
        String method = template.method();
        if ((method.equals("GET") || method.equals("PUT") || method.equals("DELETE")) && template.body() != null) {
            JsonNode jsonNode = objectMapper.readTree(template.body());
            template.body("");
            Map<String, Collection<String>> queries = new HashMap<>();
            buildQuery(jsonNode, queries);
            template.queries(queries);
        }
    }

    private void buildQuery(JsonNode jsonNode, Map<String, Collection<String>> queries) {
        Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
        while (it.hasNext()) {
            Map.Entry<String, JsonNode> entry = it.next();
            if (!StringUtils.isEmpty(entry.getValue())) {
                buildQuery(entry.getValue(), entry.getKey(), queries);
            }
        }
    }

    private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
        // 叶子节点
        if (!jsonNode.isContainerNode()) {
            if (jsonNode.isNull()) {
                return;
            }
            Collection<String> values = queries.get(path);
            if (null == values) {
                values = new ArrayList<>();
                queries.put(path, values);
            }
            values.add(jsonNode.asText());
            return;
        }
        // 数组节点
        if (jsonNode.isArray()) {
            Iterator<JsonNode> it = jsonNode.elements();
            while (it.hasNext()) {
                buildQuery(it.next(), path, queries);
            }
        }
    }

}
